Imports System.IO
Imports cmplib01
Imports FMPLib01

'<Serializable()> Public Class CampaignerCombatEngine
'    Implements ICombatEngine.ICombatEngine

'    Private Const c_Module As String = "CampaignerCombatEngine"
'    Private Const c_MaxChitDetectionLevel As Integer = 12
'    Private Const c_RoadDistance As Integer = 5

'    Private Structure Boiler
'        Public ChitMem As ChitMember
'        Public Location As Point
'        Public TerrainMod As Single
'        Public Size As Single
'        Public LosPower As Single
'        Public LosRange As Long
'        Public Detected As Boolean
'        Public OwningFactionKey As String
'        Public OwningPlayerID As Integer
'        Public ZOCRange As Integer
'    End Structure

'    Private Enum OnRoadType
'        NoRoad = 0
'        UnimprovedRoad = 1
'        ImprovedRoad = 2
'        MajorRoad = 3
'    End Enum


'    Public Event PercentComplete(ByVal percent As Integer)

'    Private m_UsesContactCombat As Boolean = True
'    Private m_UsesRangedCombat As Boolean = False
'    Private m_UsesPreCombatWindow As Boolean = True
'    Private _currentPhase As Integer = 0

'    Private contactRange As Int16 = 32 ' this is for determining if two units are touching
'    Private joinCombatDistance As Int16 = 32   ' this is for determining if a new combat should be made, or if to add the targets in question to 
'    '                                                              an existing combat.

'    Private ptrGameData As cmplib01.CampaignerGameData
'    Private ptrFMPData As FMPLib01.FlexMapData

'    Private arrDistance(10, 10) As Single ' used for distance between chits
'    'Private arrFactionA(5, 7) 'a : chit, b: 0 = gckey, 1 = x, 2 = y, 3 = terrain mod, 4 = size, 5= lospower, 6 = range, 7= detected (0/1)
'    'Private arrFactionB(5, 7)
'    Private arrFactionA(1) As Boiler
'    Private arrFactionB(1) As Boiler

'    Private detectionHalt As Boolean = False    '// once a unit is NEWLY detected, we HALT the turn there. 


'    Public Function CombatReportString() As String Implements ICombatEngine.ICombatEngine.CombatReportString
'        ' this returns a combat report in string format

'    End Function

'    Public Function CombatReportXML() As System.Xml.XmlDataDocument Implements ICombatEngine.ICombatEngine.CombatReportXML
'        ' this returns as combat report in xml format

'    End Function

'    Public Function Combats() As cmplib01.Battles Implements ICombatEngine.ICombatEngine.Combats
'        ' returns a collection of combats and whether they are finished or not.

'    End Function

'    Public Sub GenerateCombatTurn(ByRef gameData As cmplib01.CampaignerGameData, ByVal fmpData As FMPLib01.FlexMapData, ByVal PhaseCount As Short) Implements ICombatEngine.ICombatEngine.GenerateCombatTurn
'        Try
'            ptrGameData = gameData
'            ptrFMPData = fmpData

'            'Dim i As Int16
'            'Dim key As String
'            'Dim gc As cmplib01.GroundChitType
'            Dim skipBit As Byte = 0
'            Dim skipBitStop As Integer = 0 'PhaseCount / 10
'            Dim FactA As cmplib01.Faction
'            Dim fukov As String
'            Dim a As Int16 ' faction a in arrfactiona boiler
'            Dim b As Int16
'            Dim removeCollection As New Collection

'            For Each fukov In ptrGameData.Faction_g.HT.Keys
'                FactA = ptrGameData.Faction_g.Item(fukov)
'                Exit For
'            Next

'            RemoveTheDead()
'            ResetStatus()
'            ResetBoiler()
'            PopulateBoiler()

'            For _currentPhase = 0 To PhaseCount
'                Dim unit As cmplib01.UnitType
'                'TODO: Tokens. Eventually. Maybe. Who knows.
'                'Dim tok As cmplib01.TokenType

'                Try
'                    RaiseEvent PercentComplete((_currentPhase / PhaseCount) * 100)
'                Catch

'                End Try

'                ' reset boiler faction counters
'                a = 0
'                b = 0
'                For Each mem As ChitMember In ptrGameData.Chits

'                    '// only battlegroups.
'                    Select Case mem.UnitType
'                        Case GroundChitClass_cgd.Battlegroup
'                            Dim bg As BattlegroupChit = mem
'                            If MoveUnit2(bg, PhaseCount) = True Then
'                                '// uh...?
'                            End If
'                            '// historical location
'                            Try
'                                bg.historicalPosition(_currentPhase) = bg.Location
'                            Catch ex As Exception
'                                '// deal with it straight up
'                                HandleException(c_Module, ex)
'                            End Try
'                            '// and now a contact check
'                            ContactCheck(bg, _currentPhase)
'                    End Select

'                    '// skip bit stuff goes here
'                    If skipBit = 0 Then
'                        If mem.OwningFaction.Equals(FactA) Then
'                            ' if this unit is not moving, its data is not going to change
'                            If mem.Status = cmplib01.GroundUnitStatus_cgd.Moving Then
'                                ' array items 0,4,5 and 6 don't need updating
'                                arrFactionA(a).Location = mem.Location
'                                arrFactionA(a).TerrainMod = ptrFMPData.LOSCost(mem.Location)
'                            End If
'                            a += 1
'                        Else
'                            If mem.Status = cmplib01.GroundUnitStatus_cgd.Moving Then
'                                arrFactionB(b).Location = mem.Location
'                                arrFactionB(b).TerrainMod = ptrFMPData.LOSCost(mem.Location)
'                            End If
'                            b += 1
'                        End If

'                        '// moved here? maybe..
'                        PointToPointBoiler()
'                        '// we also check AreaObjectives here... perhaps.
'                        AreaObjectiveOwnership()
'                        AssignAOownership()
'                        '// here's a good spot for ZOC stuff to go. Whatchathink?
'                        'If TypeOf gc Is UnitType Then ZOCBehavior(gc)
'                        If mem.UnitType = GroundChitClass_cgd.Battlegroup Then ZOCBehavior(mem)
'                    Else
'                        '// currently, terhe are no sipks in the wohle tnihg
'                    End If

'                Next    ' chitmember

'                If detectionHalt = True Then
'                    detectionHalt = False
'                    Exit For
'                End If

'                If skipBit >= skipBitStop Then
'                    skipBit = 0
'                Else
'                    skipBit += 1
'                End If

'            Next  ' phase count

'            DecreaseDetectionForUnspotted()

'            ' titanic objects now get a +1 detection. This means that an 'unspotted' one will always have a question mark until a unit is close enough to see it.
'            IncreaseDetectionForTitanicObjects()

'            ResetDeploymentValues()
'        Catch ex As Exception
'            HandleException("CampaignerCombatEngine.GenerateTurn", ex)
'        End Try
'    End Sub

'    Private Sub IncreaseDetectionForTitanicObjects()
'        'Dim gcKey As String
'        'Dim gc As cmplib01.GroundChitType
'        Dim FactA As cmplib01.Faction
'        Dim factB As cmplib01.Faction
'        Dim fukov As String

'        For Each fukov In ptrGameData.Faction_g.HT.Keys
'            If Not FactA Is Nothing Then
'                factB = ptrGameData.Faction_g.Item(fukov)   ' if A is assigned already then we know that this is the other one. This only works with 2 factions of course.
'            End If
'            If FactA Is Nothing Then FactA = ptrGameData.Faction_g.Item(fukov)
'        Next

'        For Each mem As ChitMember In ptrGameData.Chits
'            If mem.OwningFaction.Equals(FactA) Then
'                If mem.Size > 10000 Then IncreaseDetectionOnTarget(factB, mem, False)
'            Else
'                If mem.Size > 10000 Then IncreaseDetectionOnTarget(FactA, mem, False)
'            End If
'        Next

'        'For Each gcKey In ptrGameData.AllChits.Keys
'        '    GC = ptrGameData.AllChits.Item(gcKey)
'        '    If GC.OwningFaction = FactA.FactionID Then
'        '        ' deal with titanic objects
'        '        If GC.Size >= 10000 Then
'        '            IncreaseDetectionOnTarget(factB, GC, False)
'        '        End If
'        '    Else
'        '        ' deal with titanic objects here too
'        '        If GC.Size >= 10000 Then
'        '            IncreaseDetectionOnTarget(FactA, GC, False)
'        '        End If
'        '    End If
'        'Next
'    End Sub

'    Private Sub RemoveTheDead()
'        Try
'            '// the dead should NOT go away, but you should be able to hide them... :D

'            'Dim gcKey As String
'            'Dim gc As GroundChitType
'            '            Dim removeCollection As New Collection

'            '            For Each gcKey In ptrGameData.AllChits.Keys
'            '                gc = ptrGameData.AllChits.Item(gcKey)
'            '                If gc.Status = GroundUnitStatus_cgd.Dead Then
'            '                    removeCollection.Add(gcKey)
'            '                End If
'            '            Next

'            '            For Each gcKey In removeCollection
'            '                ptrGameData.AllChits.Remove(gcKey)
'            '#If DEBUG Then
'            '                Debug.WriteLine("Removing " & gcKey)
'            '#End If
'            '            Next
'        Catch ex As Exception
'            HandleException("CampaignerCombatEngine.RemoveTheDead", ex)
'        End Try

'    End Sub

'    Private Sub AreaObjectiveOwnership()
'        Dim ao As AreaObjective
'        'Dim unit As GroundChitType
'        'Dim unitKey As String

'        '// Faction A is the first faction, Faction B is the second

'        '// reset the area objective information first.
'        ResetAOInfo()

'        Try
'            Dim mem As ChitMember
'            For Each mem In ptrGameData.Chits
'                If Not mem.Status = GroundUnitStatus_cgd.Dead OrElse Not mem.Status = GroundUnitStatus_cgd.NotDeployed Then
'                    For Each ao In ptrGameData.AreaObjectives
'                        If ao.ObjectiveRegion.IsVisible(mem.Location) Then
'                            If Not ao.FactionsPresent.Contains(mem.OwningFaction) Then
'                                ao.FactionsPresent.Add(mem.OwningFaction)
'                            End If
'                        End If
'                    Next
'                End If
'            Next
'        Catch ex As Exception
'            HandleException(c_Module, ex)
'        End Try

'        'Try
'        '    For Each unitKey In ptrGameData.AllChits.Keys
'        '        unit = ptrGameData.AllChits.Item(unitKey)
'        '        If Not unit.Status = GroundUnitStatus_cgd.Dead OrElse Not unit.Status = GroundUnitStatus_cgd.NotDeployed Then
'        '            '// run through the objectives
'        '            For Each ao In ptrGameData.AreaObjectives
'        '                If ao.ObjectiveRegion.IsVisible(unit.Location) Then
'        '                    If Not ao.FactionsPresent.Contains(ptrGameData.Faction_g.Item(cmplib01.CampaignerGameData.CDGKEY_FACTION & unit.OwningFaction)) Then
'        '                        ao.FactionsPresent.Add(ptrGameData.Faction_g.Item(cmplib01.CampaignerGameData.CDGKEY_FACTION & unit.OwningFaction))
'        '                    End If
'        '                End If
'        '            Next
'        '        End If
'        '    Next
'        'Catch ex As Exception
'        '    Stop
'        'End Try

'    End Sub

'    Private Sub ResetAOInfo()
'        Dim ao As AreaObjective
'        For Each ao In ptrGameData.AreaObjectives
'            ao.FactionsPresent = New ArrayList
'        Next
'    End Sub

'    Private Sub AssignAOownership()
'        Dim ao As AreaObjective
'        For Each ao In ptrGameData.AreaObjectives
'            Select Case ao.FactionsPresent.Count
'                Case Is = 0
'                Case Is = 1
'                    ao.OwningFaction = ao.FactionsPresent.Item(0).factionid
'                    ao.IsContested = False
'                Case Else
'                    ao.IsContested = True
'            End Select
'        Next
'    End Sub

'    Private Sub ZOCBehavior(ByRef unit As BattlegroupChit)
'        Dim closestDistance As Integer = 500000
'        Dim distance As Integer
'        Dim validEnemy As Boiler
'        Dim factA As Faction
'        Dim factAkey As String
'        Dim enemyBoil() As Boiler
'        Dim bInZOC As Boolean
'        'Dim newWap As New Point

'        '// find out which boiler array we need to use
'        '// factionA array is the first found faction in the collection

'        For Each factAkey In ptrGameData.Faction_g.HT.Keys
'            factA = unit.OwningFaction 'ptrGameData.Faction_g.Item(cmplib01.CampaignerGameData.CDGKEY_FACTION & unit.OwningFaction)
'            Exit For
'        Next

'        If factAkey = ptrGameData.CDGKEY_FACTION & unit.OwningFaction.FactionID Then
'            enemyBoil = arrFactionB

'        Else
'            enemyBoil = arrFactionA
'        End If

'        Dim this As Boiler
'        For Each this In enemyBoil
'            distance = XYDistance(unit.Location, this.Location)
'            If (distance < closestDistance) AndAlso (distance <= this.ZOCRange) Then
'                validEnemy = this
'                closestDistance = distance
'                bInZOC = True
'            End If
'        Next

'        '// now behave!
'        If Not bInZOC Then Exit Sub
'        Dim thisFact As Faction

'        If unit.OwningFaction.FactionID = factA.FactionID Then
'            thisFact = factA
'        Else
'            thisFact = unit.OwningFaction 'ptrGameData.Faction_g.Item(cmplib01.CampaignerGameData.CDGKEY_FACTION & unit.OwningFaction)
'        End If

'        'Dim target As ChitMember = ptrGameDataChits(validEnemy.ChitKey)
'        IncreaseDetectionOnTarget(thisFact, validEnemy.ChitMem)

'        Select Case unit.Order
'            Case Is = "Engage"
'                unit.waypoints.Clear()
'                Dim newWap As New SmartWaypoint
'                newWap.LOC = validEnemy.ChitMem.Location
'                unit.waypoints.add(newWap)
'            Case Is = "Withdraw"
'                unit.waypoints.Clear()
'                Dim newWap As New SmartWaypoint
'                newWap.LOC = validEnemy.Location
'                Dim xStr As Single
'                Dim yStr As Single
'                GetXYStrength(unit.Location, validEnemy.Location, xStr, yStr)
'                If validEnemy.ZOCRange > closestDistance Then
'                    newWap.LOC = validEnemy.ChitMem.Location 'xStr * (closestDistance * 2)
'                    newWap.LOC = New Point(newWap.LOC.X - (xStr * (closestDistance * 2)), newWap.LOC.Y - (yStr * (closestDistance * 2)))
'                End If

'                unit.Waypoints.Add(newWap)
'            Case Else
'                '// clear all waypoints
'                unit.Waypoints.Clear()
'        End Select

'    End Sub

'    Private Function MoveUnit2(ByRef unit As BattlegroupChit, ByVal PhaseCount As Short) As Boolean
'        Dim moveCost As Single
'        Dim moveModifier As Single
'        Dim speed As Single
'        Dim newLocation As New Point
'        Dim wap As Point
'        Dim roadBonus As Single
'        Dim sm As New SMVector
'        Dim dailyRate As Single = 1

'        Try
'            Select Case unit.Status
'                Case GroundUnitStatus_cgd.LoadingTransport, GroundUnitStatus_cgd.InTransport
'                    'unit.Status = GroundUnitStatus_cgd.InTransport
'                    ''// update the transported unit's location
'                    'unit.Location = unit.TransportingIn.Location
'                    ''// clear old waypoints for this sukka
'                    'unit.Waypoints.Clear()
'                    'Return True
'                Case GroundUnitStatus_cgd.Moving
'                Case GroundUnitStatus_cgd.OK
'                Case GroundUnitStatus_cgd.UnloadingFromTransport
'                Case Else
'                    Return False '// we're not ok to move.
'            End Select

'            If unit.Waypoints.Count = 0 Then
'                unit.Status = GroundUnitStatus_cgd.OK
'                unit.MoveRemaining = 0
'                Return False
'            End If

'            If unit.MoveRemaining <= 0 Then
'                unit.Status = GroundUnitStatus_cgd.OK
'                unit.MoveRemaining = 0
'                Return False
'            End If

'            '// Road bonus
'            Select Case PointIsOnRoad(unit.Location)
'                Case OnRoadType.NoRoad : roadBonus = 1
'                Case OnRoadType.UnimprovedRoad : roadBonus = 2
'                Case OnRoadType.ImprovedRoad : roadBonus = 3
'                Case OnRoadType.MajorRoad : roadBonus = 4
'            End Select

'            speed = unit.EffectiveSpeed / PhaseCount

'            speed *= roadBonus
'            moveModifier = ptrFMPData.MovementCost(unit.Location, unit.MovementClassID) * 0.01
'            moveCost = moveModifier

'            speed *= moveCost

'            '// now, check for daily turn rate.
'            If ptrGameData.TurnLength = TurnLength_cgd.FullDay Then
'                dailyRate = 0.25
'            End If

'            speed *= dailyRate

'            ' ''If speed < 3 Then speed = 3
'            If speed >= 3 Then
'                unit.MoveAccumulated = speed
'            Else
'                unit.MoveAccumulated += speed
'            End If

'            If unit.MoveAccumulated > 3 Then
'                speed = unit.MoveAccumulated
'                unit.MoveAccumulated = 0
'            Else
'                speed = 0
'            End If


'            '// get next coordinate (not using THIS crapola though-ola
'            wap = unit.waypoints(0).LOC

'            Dim newLocationF As PointF = sm.GeneratePtOnVector(New PointF(unit.Location.X, unit.Location.Y), New PointF(wap.X, wap.Y), speed)

'            newLocation.X = newLocationF.X
'            newLocation.Y = newLocationF.Y

'            '// check distance to end of waypoint
'            If XYDistance(unit.Location, wap) <= XYDistance(unit.Location, newLocation) Then
'                '// the waypoint is closer
'                newLocation.X = wap.X
'                newLocation.Y = wap.Y
'                unit.Waypoints.RemoveAt(0)
'            End If

'            '// check to make sure we are moving into terrain that the movement class can
'            If ptrFMPData.MovementAllowed(newLocation, unit.MovementClassID) = False Then
'                '// check for bridges? bridges allow a unit to move over 'Impassable' terrain. If you were to put a bridge
'                '// across the top of a stinking mountain, then you would be able to cross the mountain. I suppose the 
'                '// word TUNNEL should be used instead!
'                '// Flexmap should do this for us. Shouldn't it?
'                unit.InvalidWaypoint = True
'                Return False
'            End If

'            '// hmmn... roads?
'            If speed > 0 Then unit.DistanceTravelled += (speed + speed * moveCost) / roadBonus

'            ' ''If unit.DistanceTravelled > (unit.EffectiveSpeed * dailyRate) Then
'            ' ''    Return False
'            ' ''End If

'            unit.Location = newLocation

'        Catch ex As Exception
'            HandleException("CampaignerCombatEngine.MoveUnit2", ex)
'        End Try

'    End Function

'    Private Function PointIsOnRoad(ByRef hitPt As Point) As OnRoadType
'        '// returns true if the hit point is within tolerance range of any road.
'        Dim pt1 As Point
'        Dim vx As Single
'        Dim vy As Single
'        Dim bOutOfRange As Boolean

'        '\\equation of the line
'        'm = dy/dx
'        'y = mx + b
'        'a = x intercept
'        'b = y intercept
'        'ax + by + c = 0

'        Dim roadie As Road

'        For Each roadie In ptrFMPData.Roads
'            pt1.X = roadie.X1
'            pt1.Y = roadie.Y1
'            vx = roadie.X2 - roadie.X1
'            vy = roadie.Y2 - roadie.Y1
'            ' check to see if the vectors point in the same or different directions
'            If (DistPointToLine(hitPt.X, hitPt.Y, 0, pt1.X, pt1.Y, 0, vx, vy, 0, bOutOfRange)) < c_RoadDistance Then
'                If Not bOutOfRange Then
'                    Select Case roadie.RoadType
'                        Case FlexMapData.RoadType.ImprovedRoad : Return OnRoadType.ImprovedRoad
'                        Case FlexMapData.RoadType.MajorRoad : Return OnRoadType.MajorRoad
'                    End Select
'                End If
'            End If
'        Next

'        Return OnRoadType.NoRoad

'    End Function

'    Private Sub PointToPointBoiler()
'        '// this is the Point to Point detection boiler. A little different than the Orbital one. yeah.

'        '// this sub now does two detection attempts. One is 'terrain detection' where intervening terrain is
'        '// ignored, but the highest detection attainable is 2 (results in a question mark). 
'        '// the second method is a direct line of sight, where terrain between the units 'consumes' los range
'        '// This will increase the detection on the target to 'known', although, it could simply increase
'        '// each turn as it used to... hmmn.

'        Dim a As Integer
'        Dim b As Integer
'        Dim DetectingFaction As Faction
'        Dim DetectingChit As ChitMember
'        Dim TargetChit As ChitMember
'        Dim dist As Integer

'        Try
'            For a = 0 To arrFactionA.GetUpperBound(0)
'                For b = 0 To arrFactionB.GetUpperBound(0)
'                    If Not arrFactionB(b).Detected Then
'                        '// make sure we have basic range
'                        dist = XYDistance(arrFactionA(a).Location, arrFactionB(b).Location)

'                        If dist <= arrFactionA(a).LosRange Then  '// close enough!
'                            'If dist <= ptrGameData.AllChits.Item(arrFactionA(a).ChitKey).effectivelos Then
'                            DetectingChit = arrFactionA(a).ChitMem 'ptrGameData.AllChits(arrFactionA(a).ChitKey)
'                            TargetChit = arrFactionB(b).ChitMem 'ptrGameData.Chits(arrFactionB(b).ChitKey)
'                            DetectingFaction = arrFactionA(a).ChitMem.OwningFaction 'ptrGameData.Faction_g.Item(arrFactionA(a).OwningFactionKey)
'                            '// first we do a simple check (using the location of both units and their distance, etc)
'                            If DetectionCheck(DetectingChit, TargetChit) = True Then
'                                '// it is DETECTED. And so, would remain as a ?
'                                'IncreaseDetectionOnTarget(DetectingFaction, TargetChit, False)
'                                HandleDetection(DetectingFaction, TargetChit, False)
'                            End If
'                            '// this is the identification process of it. Direct line of sight.
'                            PointToPointDetection(DetectingChit, TargetChit, DetectingFaction)

'                        End If
'                    End If

'                    '// check against faction a
'                    If Not arrFactionA(a).Detected Then
'                        dist = XYDistance(arrFactionB(b).Location, arrFactionA(a).Location)
'                        If dist <= arrFactionB(b).LosRange Then
'                            DetectingChit = arrFactionB(b).ChitMem 'ptrGameData.AllChits(arrFactionB(b).ChitKey)
'                            TargetChit = arrFactionA(a).ChitMem 'ptrGameData.AllChits(arrFactionA(a).ChitKey)
'                            DetectingFaction = ptrGameData.Faction_g.Item(arrFactionB(b).OwningFactionKey)

'                            If DetectionCheck(DetectingChit, TargetChit) = True Then
'                                'IncreaseDetectionOnTarget(DetectingFaction, TargetChit, False)
'                                HandleDetection(DetectingFaction, TargetChit, False)
'                            End If

'                            '// direct identification
'                            PointToPointDetection(DetectingChit, TargetChit, DetectingFaction)
'                        End If
'                    End If
'                Next b
'            Next a
'        Catch ex As Exception
'            HandleException("CampaignerCombatEngine.PointToPointBoiler", ex)
'        End Try

'    End Sub

'    Private Sub PointToPointDetection(ByRef DetectingChit As ChitMember, ByRef TargetChit As ChitMember, ByRef DetectingFaction As Faction)
'        '// this is the point to point, meaning that the distance directly from one chit to the target chit is calculated
'        '// it will short-circuit if the detecting chit "runs out" of range. Execution should only get here IF detection is
'        '// a possibility. If the units are too far away to even detect each other, we shouldn't get here.
'        '// we never count the point from origin.

'        Dim MoveStep As Integer = 5
'        Dim TotalCost As Single
'        Dim done As Boolean
'        Dim LOSCost As Single
'        Dim i As Integer
'        Dim samplepoint As PointF
'        Dim sm As New SMVector
'        Dim diff As Single

'        Dim losRangeInPixels As Integer = DetectingChit.LOS * (ptrFMPData.PixelsPerOneMile)

'        '// we'll adjust for size baby!
'        'MIXEDMODE is the new detection mode. We don't adjust for size or power in that mode.
'        '           if the target is in the zone shown, he is spotted. Period.
'        '           if mixedmode is off (0) then we calculate using power and target size.
'#If MIXEDMODE = 0 Then
'    losRangeInPixels *= (TargetChit.Size / 100)
'#End If

'        Dim rangeToTarget As Integer = XYDistance(DetectingChit.Location, TargetChit.Location)
'        Dim currentSampleDistance As Integer

'        Try

'            Do Until done
'                i += MoveStep
'                samplepoint = sm.GeneratePtOnVector(New PointF(DetectingChit.Location.X, DetectingChit.Location.Y), New PointF(TargetChit.Location.X, TargetChit.Location.Y), i)

'                LOSCost = ptrFMPData.LOSCost(New Point(samplepoint.X, samplepoint.Y))

'#If MIXEDMODE = 0 Then
'    '// adjust for LOS Power!! POWER POWER POWER!!
'    If LOSCost > 1 Then
'        diff = LOSCost - 1
'        diff *= (DetectingChit.LOSPower / 100)
'        LOSCost = diff + 1
'        If LOSCost < 1 Then LOSCost = 1
'    End If
'#End If

'                TotalCost += MoveStep * LOSCost

'                currentSampleDistance = XYDistance(New Point(samplepoint.X, samplepoint.Y), DetectingChit.Location)
'                If currentSampleDistance >= rangeToTarget Then
'                    '// detected
'#If MIXEDMODE = 0 Then
'    IncreaseDetectionOnTarget(DetectingFaction, TargetChit)
'#Else
'                    '// if we're in mixedmode, the unit is completely detected.
'                    IncreaseDetectionOnTarget(DetectingFaction, TargetChit, True)
'#End If

'                    done = True
'                End If

'                If TotalCost >= losRangeInPixels / 2 Then
'                    '// not so detected
'                    done = True
'                End If
'            Loop

'        Catch ex As Exception
'            HandleException("Campaigner Combat Engine.PointToPointDetection", ex)
'        End Try

'    End Sub

'    Private Sub LOSBoiler()
'        ' this sub crunches the data 
'        Dim a As Integer
'        Dim b As Integer
'        Dim SomeFact As cmplib01.Faction
'        Dim SomeChit As ChitMember

'        For a = 0 To arrFactionA.GetUpperBound(0)
'            For b = 0 To arrFactionB.GetUpperBound(0)
'                ' check against faction b, if not already detected this turn
'                If arrFactionB(b).Detected = False Then
'                    If LOSCheck(arrFactionA(a), arrFactionB(b)) = True Then
'                        arrFactionB(b).Detected = True
'                        ' find this newly targeted chit
'                        SomeChit = arrFactionB(b).ChitMem 'ptrGameData.AllChits(arrFactionB(b).ChitKey)
'                        SomeFact = ptrGameData.Faction_g.Item(arrFactionA(a).OwningFactionKey)
'                        IncreaseDetectionOnTarget(SomeFact, SomeChit)
'                    End If
'                End If
'                ' check against faction a, if not already detected this turn
'                If arrFactionA(a).Detected = False Then
'                    If LOSCheck(arrFactionB(b), arrFactionA(a)) = True Then
'                        arrFactionA(a).Detected = True
'                        ' find this newly targeted chit
'                        SomeChit = arrFactionA(a).ChitMem 'ptrGameData.AllChits(arrFactionA(a).ChitKey)
'                        SomeFact = ptrGameData.Faction_g.Item(arrFactionB(b).OwningFactionKey)
'                        IncreaseDetectionOnTarget(SomeFact, SomeChit)
'                    End If
'                End If
'            Next b
'        Next a

'    End Sub

'    Private Function LOSCheck(ByVal detecter As Boiler, ByVal target As Boiler) As Boolean
'        ' basic LOS rules calculate LOS range, LOS power, Target Size, Target Terrain LOS cost, detecter terrain LOS cost
'        Dim modifiedDistance As Int32
'        Dim trueDistance As Int32        ' this is to determine if a unit or objective is outside the possible detection range.
'        Dim DetectingTerrainCost As Single
'        Dim TargetTerrainCost As Single
'        Dim TargetSize As Single

'        ' The actual distance in pixels between the chits
'        trueDistance = XYDistance(detecter.Location.X, target.Location.X, detecter.Location.Y, target.Location.Y)

'        'If trueDistance < detecter.LosRange Then
'        ' modified distance is where we begin trashing the distance!
'        modifiedDistance = trueDistance   'well, it has to start somewhere

'        ' add each of the distance costs, using the TRUEdistance as starting point
'        TargetTerrainCost = modifiedDistance - (modifiedDistance * target.TerrainMod)
'        DetectingTerrainCost = modifiedDistance - (modifiedDistance * detecter.TerrainMod)
'        modifiedDistance += TargetTerrainCost + DetectingTerrainCost

'        ' Modify by Target Size. We're using the MODIFIED distance (coefficient model)
'        TargetSize = target.Size
'        modifiedDistance += (modifiedDistance - (modifiedDistance * TargetSize))

'        ' Modify by Detecting Power, again, using coefficient model 
'        modifiedDistance -= ((modifiedDistance * detecter.LosPower) - modifiedDistance)

'        If modifiedDistance < detecter.LosRange Then
'            Return True
'        Else
'            Return False
'        End If
'        'End If

'    End Function

'    Private Function DetectionCheck(ByRef detecter As ChitMember, ByRef target As ChitMember) As Boolean
'        '// it uses the distance, LOS POWER, LOS Cost of both target and detecter and size. Yum.
'        Try
'            Dim TrueDistance As Int32
'            Dim modifiedDistance As Int32
'            Dim detectingTerrainCost As Single
'            Dim targetTerrainCost As Single
'            Dim detectPower As Single
'            Dim targetSize As Single
'            Dim modifiedLOS As Single

'            '// parameters to take into consideration:

'            '___PARAMETER_____________________________________________EFFECT___________________________
'            ' terrain cost at both target and detecter          increases modified range
'            ' size of target                                    increases detection range
'            ' power of detecter                                 modifies detection range


'            ' The actual distance in pixels between the chits
'            TrueDistance = XYDistance(detecter.Location.X, target.Location.X, detecter.Location.Y, target.Location.Y)

'            ' modified distance is where we begin trashing the distance!
'            modifiedDistance = TrueDistance   'well, it has to start somewhere

'            '// PARAMETER 1: Terrain Costs
'            modifiedDistance *= (ptrFMPData.LOSCost(target.Location) + ptrFMPData.LOSCost(detecter.Location))

'            '// we use the detecter power to increase apparent detection range
'            modifiedLOS = (detecter.LOS * ptrFMPData.PixelsPerOneMile())

'            Debug.WriteLine("Called in phase " & _currentPhase)

'            '.....................here's a temporary short circuit
'            If TrueDistance <= modifiedLOS Then

'                Debug.WriteLine("Fucking TRUE.")

'                Return True
'            Else
'                Return False
'            End If

'            '/////////////////////////////////////////////////////////////////////// no extra stufff.

'            modifiedLOS *= (detecter.LOSPower / 100)
'            modifiedLOS *= (target.Size / 100)

'            ' Modify by Target Size. We're using the MODIFIED distance (coefficient model)
'            'targetSize = target.Size

'            If modifiedDistance < modifiedLOS Then
'                Return True
'            Else
'#If DEBUG Then
'                Debug.WriteLine(modifiedDistance & " < " & modifiedLOS)
'#End If
'                Return False
'            End If


'        Catch ex As Exception
'            HandleException("CampaignerCombatEngine.DetectionCheck", ex)
'        End Try

'    End Function

'    Private Sub ContactCheck(ByRef unit As ChitMember, ByVal inPhase As Integer)
'        ' A unit may be in multiple battles?
'        Dim key As String
'        Dim gc As cmplib01.GroundChitType
'        Dim enemyObj As ChitMember
'        Dim enemyUnit As ChitMember
'        'Dim enemyTok As cmplib01.TokenType

'        Try

'            Dim chit As ChitMember
'            For Each chit In ptrGameData.Chits
'                If chit.Status <> GroundUnitStatus_cgd.Dead Then
'                    If unit.OwningFaction.FactionID <> chit.OwningFaction.FactionID Then
'                        '// test range
'                        If XYDistance(unit.Location, chit.Location) <= contactRange Then
'                            If chit.UnitType = GroundChitClass_cgd.Objective Then
'                                enemyObj = chit
'                                Createbattle(unit, enemyObj, inPhase)
'                                SetCombatFlag(unit, enemyObj)
'                            End If
'                            enemyUnit = chit
'                            Createbattle(unit, enemyUnit, inPhase)
'                            SetCombatFlag(unit, enemyUnit)
'                        End If
'                    End If
'                End If
'            Next

'            '// increase detection to known.
'            IncreaseDetectionOnTarget(unit.OwningFaction, unit, True)
'            IncreaseDetectionOnTarget(chit.OwningFaction, chit, True)

'        Catch ex As Exception
'            HandleException(c_Module, ex)
'        End Try

'    End Sub

'    Private Function IsChaseOn(ByRef unit As UnitType, ByRef target As UnitType) As Boolean
'        '// if one guy is trying to get away (withdraw) and the other is engaging, the chase is on.
'        Try

'            If unit.Order.ToLower = "withdraw" Then

'            ElseIf target.Order.ToLower = "withdraw" Then

'            Else
'                '// neither is on withdraw
'                Return False
'            End If

'        Catch ex As Exception
'            HandleException("CampaignerCombatEngine.IsChaseOn", ex)
'        End Try

'    End Function

'    Private Sub BeginChase(ByRef unit As UnitType, ByRef target As UnitType)
'        '// it doesn't matter who is running (unit or target), its all handled the same.
'        Try
'            '// first find out who is running away

'            '// set up the waypoints

'            '// let 'em rip.


'        Catch ex As Exception
'            HandleException("CampaignerCombatEngine.IsChaseOn", ex)
'        End Try
'    End Sub

'    Private Sub Createbattle(ByRef unit As ChitMember, ByRef target As ChitMember, ByVal inPhase As Integer)
'        ' creates a battle, or checks to see if the besieged unit is already in combat, or if there is a combat in this
'        ' location already? Hmnn. We don't want to add duplicates. Combat is in the location of the initial contact.
'        ' This is the battle LOCATION. Attacking and Defending chit have absolutely no meaning, really.
'        ' using the rules found in CampaignerCombat.txt, determine if a new combat should be made, or if these
'        ' units should be added to an existing combat.
'        ' the unit being bumped into is considered the 'defender'. Additional units are marked as defendingsupport or attackingsupport
'        ' marks the battle as active in a particular phase

'        ' 1 check to see if target unit is already engaged, if so, add 'unit' to the battle targetunit is involved in.
'        ' 2 check to see if this combat would be within 'joinCombatRange', from EITHER units' point of view, if so, add them both.
'        ' 3 if either '1' or '2' do not apply, create a new combat.
'        Dim batt As cmplib01.Battle_2

'        ' if there are no battles currently in the list, we don't need any checks we just create a new battle and exit
'        If ptrGameData.Battles_g.HT.Count = 0 Then
'            AddNewbattle(unit, target, inPhase)
'            Exit Sub
'        End If

'        If target.Status = cmplib01.GroundUnitStatus_cgd.Engaged Then
'            Try
'                batt = target.battleInvolvedIn
'                ' add the new contact to this combat.
'                batt.InvolvedChits.add(unit)
'                unit.Status = cmplib01.GroundUnitStatus_cgd.Engaged
'                ' also set this unit to supporting attack or defense, depending on ORIGINAL units.
'                SetUnitbattlePosture(unit, batt)
'                ' and now, get the hell out!
'                Exit Sub
'            Catch argEx As ArgumentException
'                Exit Sub
'            Catch ex As Exception
'                HandleException(c_Module, ex)
'                Exit Sub
'            End Try
'        End If
'        ' target is NOT already engaged in combat, check range to existing combats (if we are down here,
'        ' we already know there are other combats occuring), if within range, add both units to that combat.
'        ' both of these units are considered supporting their faction, whether its attacking or defending (check the units involved 
'        ' list to make sure the correct battleposture is set.
'        Dim key As String
'        Dim distOne As Int16
'        Dim distTwo As Int16
'        Dim closeDist As Int16
'        Dim closestDist As Int16 = 30000
'        Dim closestbattleKey As String

'        For Each key In ptrGameData.Battles_g.HT.Keys
'            batt = ptrGameData.Battles_g.Item(key)
'            distOne = XYDistance(unit.Location.X, batt.BattleLocation.X, unit.Location.Y, batt.BattleLocation.Y)
'            distTwo = XYDistance(target.Location.X, batt.BattleLocation.X, target.Location.Y, batt.BattleLocation.Y)
'            If distOne < distTwo Then
'                closeDist = distOne
'            Else
'                closeDist = distTwo
'            End If
'            ' we are trying to determine which battle is the closest
'            If closeDist < closestDist Then
'                closestbattleKey = batt.Key
'                closestDist = closeDist
'            End If
'        Next
'        ' determine the distance from the closest unit (to the closest battle)
'        If closestDist <= joinCombatDistance Then
'            ' add both units to the closest battle, and then set their battle posture
'            Try
'                batt = ptrGameData.Battles_g.Item(closestbattleKey)
'                batt.InvolvedChits.add(unit)
'                batt.InvolvedChits.add(unit)
'                target.Status = cmplib01.GroundUnitStatus_cgd.Engaged
'                unit.Status = cmplib01.GroundUnitStatus_cgd.Engaged
'                ' set the units battle postures accordingly
'                SetUnitbattlePosture(unit, batt)
'                SetUnitbattlePosture(target, batt)
'            Catch ex As Exception
'                HandleException(c_Module, ex)
'            End Try
'        Else
'            AddNewbattle(unit, target, inPhase)
'        End If

'    End Sub

'    Private Sub SetCombatFlag(ByRef ptrUnit As ChitMember, ByRef ptrTarget As ChitMember)
'        ' finds the owning player and sets his IsInCombat flag.
'        Dim playKey As String
'        Dim play As cmplib01.Player

'        For Each playKey In ptrGameData.Players.Keys
'            play = ptrGameData.Players.Item(playKey)
'            If play.PlayerID = ptrUnit.OwningPlayer.PlayerID Then
'                play.IsInCombat = True
'            End If
'            If play.PlayerID = ptrTarget.OwningPlayer.PlayerID Then
'                play.IsInCombat = True
'            End If
'        Next

'    End Sub

'    Private Sub SetCombatFlag(ByRef ptrUnit As cmplib01.UnitType, ByRef ptrTarget As cmplib01.ObjectiveType)
'        Dim factID As Integer = ptrTarget.OwningFaction
'        Dim factKey As String = "FACT" & factID
'        Dim playKey As String
'        Dim play As cmplib01.Player

'        For Each playKey In ptrGameData.Players.Keys
'            play = ptrGameData.Players.Item(playKey)
'            If play.PlayerID = ptrUnit.OwningPlayer Then
'                play.IsInCombat = True
'            End If
'            If play.FactionKey = factKey Then
'                play.IsInCombat = True
'            End If
'        Next

'    End Sub

'    Private Sub SetUnitbattlePosture(ByRef unit As ChitMember, ByRef batt As cmplib01.Battle)
'        'Dim testUnit As cmplib01.GroundChitType
'        'Dim key As String

'        For Each mem As ChitMember In batt.InvolvedChits
'            If mem.OwningFaction.Equals(unit.OwningFaction) Then
'                If mem.battleInvolvedIn.Equals(unit.battleInvolvedIn) Then
'                    unit.currentbattleposture = mem.currentbattleposture
'                End If
'            End If
'        Next

'        ' TODO: This handles only TWO factions involved.
'        'For Each key In batt.InvolvedChits.Keys
'        '    testUnit = batt.InvolvedChits.item(key)
'        '    If testUnit.OwningFaction = unit.OwningFaction Then
'        '        If testUnit.BattleInvolvedInID = unit.BattleInvolvedInID Then
'        '            unit.CurrentBattlePosture = testUnit.CurrentBattlePosture
'        '            Exit For
'        '        End If
'        '    End If
'        'Next

'    End Sub

'    Private Sub ResetStatus()
'        ' resets things like detectedthisturn and such
'        Dim key As String
'        Dim gc As cmplib01.GroundChitType
'        Dim unit As cmplib01.UnitType
'        Dim pixelsPerOneMile As Single = ptrFMPData.MapScale.PixelCount / ptrFMPData.MapScale.MilesPerPixelCount
'        Dim turnMultiplier As Single  ' used to get the correct speed of a unit

'        For Each mem As ChitMember In ptrGameData.Chits
'            Select Case mem.UnitType
'                Case GroundChitClass_cgd.Battlegroup
'                    Dim batt As BattlegroupChit = DirectCast(mem, BattlegroupChit)

'                    ResetGroundUnitStatus(batt)

'                    batt.currentBattlePosture = BattlePosture_cgd.NoBattle
'                    batt.invalidWaypoint = False
'                    batt.distanceTravelled = 0
'                    batt.detectedThisTurn = False

'                    ' determine how many pixels a unit can move per game turn.
'                    Select Case ptrGameData.TurnLength
'                        Case cmplib01.TurnLength_cgd.Hour : turnMultiplier = 1
'                        Case cmplib01.TurnLength_cgd.HalfDay : turnMultiplier = 5 ' we move up to 10 hours per day
'                        Case cmplib01.TurnLength_cgd.FullDay : turnMultiplier = 10
'                        Case cmplib01.TurnLength_cgd.Week : turnMultiplier = 70
'                        Case cmplib01.TurnLength_cgd.Month : turnMultiplier = 300
'                        Case cmplib01.TurnLength_cgd.HalfHour : turnMultiplier = 0.5
'                        Case cmplib01.TurnLength_cgd.FifteenMinute : turnMultiplier = 0.25
'                        Case cmplib01.TurnLength_cgd.FiveMinute : turnMultiplier = 0.08
'                    End Select

'                    batt.effectiveSpeed = batt.movementSpeed * pixelsPerOneMile * turnMultiplier
'                    batt.moveRemaining = batt.movementSpeed * pixelsPerOneMile * turnMultiplier
'                Case GroundChitClass_cgd.Objective
'                    mem.detectedThisTurn = False
'                    mem.currentBattlePosture = BattlePosture_cgd.NoBattle

'            End Select
'        Next

'        'For Each key In ptrGameData.AllChits.Keys
'        '    gc = ptrGameData.AllChits.Item(key)
'        '    If gc.GroundChitClass = cmplib01.GroundChitClass_cgd.Unit Then
'        '        unit = gc

'        '        '// here we set up the movement value for it if its a battlegroup (transport, etc)
'        '        If TypeOf gc Is BattleGroup Then BattlegroupSetup(gc)

'        '        ' apply the GroundUnitStatus rules
'        '        ResetGroundUnitStatus(unit)
'        '        '// other properties
'        '        unit.DetectedThisTurn = False
'        '        unit.CurrentBattlePosture = cmplib01.BattlePosture_cgd.NoBattle
'        '        unit.TotalDistanceMovedThisTurn = 0
'        '        unit.InvalidWaypoint = False
'        '        unit.DistanceTravelled = 0
'        '        ' reset maximum movement
'        '        ' determine how many pixels a unit can move per game turn.
'        '        Select Case ptrGameData.TurnLength
'        '            Case cmplib01.TurnLength_cgd.Hour : turnMultiplier = 1
'        '            Case cmplib01.TurnLength_cgd.HalfDay : turnMultiplier = 5 ' we move up to 10 hours per day
'        '            Case cmplib01.TurnLength_cgd.FullDay : turnMultiplier = 10
'        '            Case cmplib01.TurnLength_cgd.Week : turnMultiplier = 70
'        '            Case cmplib01.TurnLength_cgd.Month : turnMultiplier = 300
'        '            Case cmplib01.TurnLength_cgd.HalfHour : turnMultiplier = 0.5
'        '            Case cmplib01.TurnLength_cgd.FifteenMinute : turnMultiplier = 0.25
'        '            Case cmplib01.TurnLength_cgd.FiveMinute : turnMultiplier = 0.08
'        '        End Select

'        '        unit.EffectiveSpeed = unit.MovementSpeed * pixelsPerOneMile * turnMultiplier
'        '        unit.MoveRemaining = unit.MovementSpeed * pixelsPerOneMile * turnMultiplier

'        '    ElseIf gc.GroundChitClass = cmplib01.GroundChitClass_cgd.Objective Then
'        '        gc.DetectedThisTurn = False
'        '        gc.CurrentBattlePosture = cmplib01.BattlePosture_cgd.NoBattle
'        '    End If
'        'Next

'        ' until we actually handle combat, we'll remove all of the battles
'        For Each key In ptrGameData.Battles_g.HT.Keys
'            ptrGameData.Battles_g.HT.Clear()
'        Next

'    End Sub

'    Private Sub BattlegroupSetup(ByRef BG As BattlegroupChit)
'        'Try
'        '// here's what we do...
'        '// check capacity vs transports (if there's not enough transports, we're done)
'        '// check each non-transportable speed and type
'        '// get the slowest movement speed, and use that.

'        BG.calculateProperties()

'        '    Dim tTransportCap As Integer
'        '    Dim tTransportCost As Integer
'        '    Dim canTransport As Boolean
'        '    Dim un As UnitType
'        '    Dim slowTransportableSpeed As Integer = 2000 '// this is the speed of the slowest transportable unit
'        '    Dim slowVehicle As Integer = 2000   '// the speed of the slowest non-transportable unit

'        '    For Each un In BG.Units
'        '        If un.CanTransport Then
'        '            '// mark its speed (this is a transport)
'        '            tTransportCap += un.TransportCapacity
'        '            If slowVehicle > un.MovementSpeed Then slowVehicle = un.MovementSpeed
'        '        ElseIf un.CanBeTransported = True Then '// (this can be transported)
'        '            '// total its trans cost and mark its speed
'        '            tTransportCost += un.TransportCost
'        '            If slowTransportableSpeed > un.MovementSpeed Then slowTransportableSpeed = un.MovementSpeed
'        '        Else
'        '            '// this is a non-transportable unit.
'        '            If slowVehicle > un.MovementSpeed Then slowVehicle = un.MovementSpeed
'        '        End If
'        '    Next

'        '    '// total up the cost and compare to the capability.
'        '    If tTransportCost > tTransportCap Then
'        '        '// no transporting going on, the cost is greater than capacity.
'        '        If slowTransportableSpeed < slowVehicle Then
'        '            BG.MovementSpeed = slowTransportableSpeed
'        '        Else
'        '            BG.MovementSpeed = slowVehicle
'        '        End If
'        '    Else
'        '        '// all of the transportable units can be transported. Now, use the slowest "vehicle" speed
'        '        BG.MovementSpeed = slowVehicle
'        '    End If

'        'Catch ex As Exception
'        '    HandleException("CampaignerCombatEngine.BattlegroupSetup", ex)
'        'End Try
'    End Sub

'    Private Sub ResetBoiler()
'        ' populate the distance array size
'        Dim factAChitCount As Integer
'        Dim factBChitCount As Integer
'        Dim FactA As cmplib01.Faction
'        Dim fukov As String

'        For Each fukov In ptrGameData.Faction_g.HT.Keys
'            FactA = ptrGameData.Faction_g.Item(fukov)
'            Exit For
'        Next


'        For Each mem As ChitMember In ptrGameData.Chits
'            If mem.OwningFaction.Equals(FactA) Then
'                factachitcount += 1
'            Else
'                factBChitCount += 1
'            End If
'        Next

'        ReDim arrFactionA(factAChitCount - 1)
'        ReDim arrFactionB(factBChitCount - 1)

'    End Sub

'    Private Sub PopulateBoiler()
'        Dim a As Integer
'        Dim b As Integer
'        'Dim gcKey As String
'        'Dim gc As cmplib01.GroundChitType
'        Dim FactA As cmplib01.Faction
'        Dim fukov As String

'        For Each fukov In ptrGameData.Faction_g.HT.Keys
'            FactA = ptrGameData.Faction_g.Item(fukov)
'            Exit For
'        Next

'        For Each mem As ChitMember In ptrGameData.Chits
'            If mem.OwningFaction.Equals(FactA) Then
'                arrFactionA(a).ChitMem = mem
'                arrFactionA(a).Location = mem.Location
'                arrFactionA(a).TerrainMod = 1    ' ok. so like... none yet.
'                arrFactionA(a).Size = (mem.Size * 0.01)
'                arrFactionA(a).LosPower = mem.LOSPower * 0.01
'                arrFactionA(a).LosRange = (mem.LOS / 2) * ptrFMPData.PixelsPerOneMile
'                arrFactionA(a).Detected = 0 ' not detected really. Nope. Well... not yet.
'                arrFactionA(a).OwningFactionKey = ptrGameData.CDGKEY_FACTION & mem.OwningFaction.FactionID
'                arrFactionA(a).ZOCRange = (mem.ZOC * ptrFMPData.PixelsPerOneMile) / 2
'                a += 1
'            Else
'                arrFactionB(b).ChitMem = mem
'                arrFactionB(b).Location = mem.Location
'                arrFactionB(b).TerrainMod = 1    ' ok. so like... none yet.
'                arrFactionB(b).Size = (mem.Size * 0.01)
'                arrFactionB(b).LosPower = mem.LOSPower * 0.01
'                arrFactionB(b).LosRange = (mem.LOS / 2) * ptrFMPData.PixelsPerOneMile
'                arrFactionB(b).Detected = 0 ' not detected really. Nope. Well... not yet.                
'                arrFactionB(b).OwningFactionKey = ptrGameData.CDGKEY_FACTION & mem.OwningFaction.FactionID
'                arrFactionB(b).ZOCRange = (mem.ZOC * ptrFMPData.PixelsPerOneMile) / 2
'            End If
'        Next

'    End Sub

'    Private Sub ResetGroundUnitStatus(ByRef gc As ChitMember)
'        Select Case gc.Status
'            Case cmplib01.GroundUnitStatus_cgd.Regrouping
'                ' after losing a battle, the chit must regroup. It can't move until after it is "Regrouped"
'                gc.Status = cmplib01.GroundUnitStatus_cgd.Regrouped
'            Case GroundUnitStatus_cgd.InTransport, GroundUnitStatus_cgd.LoadingTransport
'                gc.Status = GroundUnitStatus_cgd.InTransport
'            Case GroundUnitStatus_cgd.UnloadingFromTransport
'                gc.Status = GroundUnitStatus_cgd.OK
'            Case Else
'                gc.Status = cmplib01.GroundUnitStatus_cgd.OK
'        End Select
'    End Sub

'    Private Sub AddNewbattle(ByRef unit As ChitMember, ByRef targetUnit As ChitMember, ByVal inPhase As Integer)
'        ' if both units are moving, the battle is located between them, if one is not moving, the battle is located at HIS coords
'        ' TODO: make the battle at the correct location depending on who is moving, plus other rules that will most likely become
'        ' apparent after a beta game is running.
'        Dim batt As New cmplib01.Battle_2
'        Try
'            batt.BattleLocation = LocateNewbattle(unit.Location, targetUnit.Location)
'            batt.InvolvedChits.add(unit)
'            batt.InvolvedChits.add(targetUnit)

'            batt.PhaseActive = inPhase

'            batt.BattleName = unit.Name & " vs " & targetUnit.Name
'            targetUnit.Status = cmplib01.GroundUnitStatus_cgd.Engaged
'            targetUnit.battleInvolvedIn = batt
'            unit.Status = cmplib01.GroundUnitStatus_cgd.Engaged
'            unit.battleInvolvedIn = batt

'            ' the unit being bumped into is considered  'defending', the other is 'attacking'
'            unit.CurrentBattlePosture = cmplib01.BattlePosture_cgd.Attacking
'            targetUnit.CurrentBattlePosture = cmplib01.BattlePosture_cgd.Defending

'            ' apply the correct faction ids to attacking and defending in the battle for future reference.
'            batt.AttackingFactionID = unit.OwningFaction.FactionID
'            batt.DefendingFactionID = targetUnit.OwningFaction.FactionID

'            ptrGameData.Battles_g.Add(batt, batt.Key)

'        Catch ex As Exception
'            HandleException(c_Module, ex)
'        End Try

'    End Sub

'    Private Function LocateNewbattle(ByVal pntone As Point, ByVal pnttwo As Point) As Point
'        ' new battles are located between the two units (points provided)
'        Dim distance As Int32 = (XYDistance(pntone.X, pnttwo.X, pntone.Y, pnttwo.Y) / 2)
'        Dim xStr As Single = GetXorYStrength(cmXorY.cmX, pntone.X, pnttwo.X, pntone.Y, pnttwo.Y)
'        Dim yStr As Single = GetXorYStrength(cmXorY.cmY, pntone.X, pnttwo.X, pntone.Y, pnttwo.Y)
'        Dim location As New Point

'        location.X = pntone.X + (distance * xStr)
'        location.Y = pntone.Y + (distance * yStr)

'        Return location
'    End Function

'    Private Sub IncreaseDetectionOnTarget(ByRef fact As cmplib01.Faction, ByRef target As ChitMember, Optional ByVal ToKnown As Boolean = True)
'        ' increases the detection level on a particular unit
'        ' These are the DETECTION RULES.
'        ' the ToKnown parameter automatically raises the detection level to KNOWN.
'        Dim key As String = target.Name

'        If Not ToKnown Then
'            ' if it is toknown, then we don't care if its been detected or not. It becomes KNOWN!
'            If target.detectedThisTurn = True Then Exit Sub
'        End If

'        ' see if this unit already exists in the faction's contact list, if it does increase the detection level, if not, add one.
'        If fact.HTChitDetection.ContainsKey(key) Then
'            Dim det As cmplib01.ChitDetection = fact.HTChitDetection.Item(key)
'            If ToKnown = True Then
'                det.DetectionLevel = c_MaxChitDetectionLevel
'            Else

'#If MIXEDMODE = 1 Then
'                If det.ChitDetectedThisTurn = False Then
'                    '// if we were already detected, we don't need to do anything, so huzzah.
'                    det.DetectionLevel = 2
'                End If

'#Else
'                '// increase detection by one
'                det.DetectionLevel += 1
'#End If

'                If det.DetectionLevel > c_MaxChitDetectionLevel Then det.DetectionLevel = c_MaxChitDetectionLevel
'            End If

'            target.DetectedThisTurn = True
'            det.ChitDetectedThisTurn = True
'        Else
'            '// nothing special needs to be done if it isn't already in the list. :D
'            Dim det As New cmplib01.ChitDetection

'            det.ChitDetectedThisTurn = True

'            If ToKnown = True Then
'                det.DetectionLevel = c_MaxChitDetectionLevel
'            Else
'                det.DetectionLevel = 2
'            End If

'            det.ChitKey = key
'            fact.HTChitDetection.Add(key, det)
'            target.DetectedThisTurn = True

'        End If

'    End Sub

'    Private Sub HandleDetection(ByRef fact As cmplib01.Faction, ByRef target As ChitMember, Optional ByVal toKnown As Boolean = True)
'        Try
'            Dim key As String = target.Name

'            'If TypeOf target Is UnitType Then
'            '    key = target.Key
'            'Else
'            '    key = target.Key & ":" & target.Location.X & "-" & target.Location.Y
'            'End If

'            '// we don't have to do anything else if this guy was detected already, and its not a 'toknown'.
'            If toKnown = False And target.DetectedThisTurn = True Then Exit Sub

'            '// see if there is an entry for this sukka
'            If fact.HTChitDetection.ContainsKey(key) Then
'                Dim det As ChitDetection = fact.HTChitDetection.Item(key)

'                '//////////////////////NEW//////////////////////
'                'If det.DetectionLevel < 3 Then
'                '// this guy had left detection and now is back. This is a detection halt
'                detectionHalt = True
'                'End If
'                '//////////////////////NEW//////////////////////

'                If toKnown Then
'                    det.DetectionLevel = c_MaxChitDetectionLevel
'                Else
'                    det.DetectionLevel = 3
'                End If
'                det.ChitDetectedThisTurn = True
'                target.DetectedThisTurn = True
'                det.PhaseDetected = _currentPhase
'            Else
'                '// does not exist.
'                Dim det As New ChitDetection
'                det.ChitDetectedThisTurn = True

'                '//////////////////////NEW//////////////////////
'                detectionHalt = True    '// this is definately a detection halt.
'                '//////////////////////NEW//////////////////////

'                If toKnown Then
'                    det.DetectionLevel = c_MaxChitDetectionLevel
'                Else
'                    det.DetectionLevel = 3
'                End If

'                det.ChitKey = key
'                target.DetectedThisTurn = True
'                det.PhaseDetected = _currentPhase
'                fact.HTChitDetection.Add(key, det)
'            End If


'        Catch ex As Exception
'            HandleException(c_Module, ex)
'        End Try

'    End Sub

'    Private Sub DecreaseDetectionForUnspotted()
'        ' reduces the detection level on each unit that was no longer spotted this turn
'        Dim factKey As String
'        Dim fact As cmplib01.Faction

'        'TODO: new look at decreasing detection needed.
'        For Each mem As ChitMember In ptrGameData.Chits
'            If mem.detectedThisTurn = False Then
'                For Each factKey In ptrGameData.Faction_g.HT.Keys
'                    fact = ptrGameData.Faction_g.Item(factKey)
'                    If mem.OwningFaction.FactionID <> fact.FactionID Then
'                        Dim det As ChitDetection = fact.HTChitDetection.Item(mem.Name)
'                        If det.DetectionLevel > 2 Then
'                            det.DetectionLevel = 1
'                            Exit For
'                        Else
'                            det.DetectionLevel = 0
'                            Exit For
'                        End If
'                    End If
'                Next
'            End If
'        Next


'        'For Each gcKey In ptrGameData.AllChits.Keys
'        '    gc = ptrGameData.AllChits.Item(gcKey)
'        '    If gc.DetectedThisTurn = False Then
'        '        ' see if this unit exists in enemy detectionlist
'        '        For Each factKey In ptrGameData.Faction_g.HT.Keys
'        '            fact = ptrGameData.Faction_g.Item(factKey)
'        '            If gc.OwningFaction <> fact.FactionID Then
'        '                ' see if this ground chit is in this faction's list

'        '                If fact.HTChitDetection.ContainsKey(gcKey) Then
'        '                    Dim det As cmplib01.ChitDetection = fact.HTChitDetection.Item(gcKey)
'        '                    If det.DetectionLevel > 2 Then
'        '                        det.DetectionLevel = 1
'        '                        Exit For
'        '                    Else
'        '                        det.DetectionLevel = 0
'        '                        Exit For
'        '                    End If
'        '                End If
'        '            End If
'        '        Next
'        '    End If
'        'Next

'    End Sub

'    Private Sub ResetDeploymentValues()
'        ' resets the deploymentzone amount available in this turn.
'        Dim dep As cmplib01.DeploymentZone
'        Dim depKey As String

'        For Each depKey In ptrGameData.DeploymentZones_g.HT.Keys
'            dep = ptrGameData.DeploymentZones_g.HT.Item(depKey)
'            dep.PointsDeployedThisTurn = 0
'        Next
'    End Sub



'#Region "Implemented Methods"
'    Public Sub OpenCombatEngine(ByVal filePath As String) Implements ICombatEngine.ICombatEngine.OpenCombatEngine

'    End Sub

'    Public Sub SaveCombatEngine(ByVal filePath As String) Implements ICombatEngine.ICombatEngine.SaveCombatEngine

'    End Sub

'    Public Sub ShowPostCombatWindow() Implements ICombatEngine.ICombatEngine.ShowPostCombatWindow

'    End Sub

'    Public Sub ShowPreCombatWindow() Implements ICombatEngine.ICombatEngine.ShowPreCombatWindow

'    End Sub
'#End Region

'#Region "After Combat"

'    Public Sub ApplyCombatResults(ByRef GameData As cmplib01.CampaignerGameData)
'        ' checks each battle and moves any units that need to be moved and reassigns objectives to victorous units.
'        Dim key As String
'        Dim batt As cmplib01.Battle
'        Dim gc As cmplib01.GroundChitType
'        Dim unit As cmplib01.UnitType
'        Dim obj As cmplib01.ObjectiveType
'        Dim gcKey As String

'        If GameData.Battles_g.HT.Count > 0 Then
'            ' step through each battle
'            For Each key In GameData.Battles_g.HT.Keys
'                batt = GameData.Battles_g.Item(key)

'                For Each mem As ChitMember In batt.InvolvedChits
'                    If mem.Status = GroundUnitStatus_cgd.Dead Then
'                        '// uh
'                    Else
'                        If mem.UnitType = GroundChitClass_cgd.Battlegroup Then
'                            UnitbattleResult(mem, batt)
'                        ElseIf mem.UnitType = GroundChitClass_cgd.Objective Then
'                            ObjectivebattleResult(mem, batt, GameData)
'                        End If

'                    End If
'                Next

'            Next key
'        Else
'            Exit Sub
'        End If

'    End Sub

'    Private Sub UnitbattleResult(ByRef unit As ChitMember, ByVal batt As cmplib01.Battle)
'        ' used to apply the correct result to a unit
'        Dim battlelocation As Point = batt.BattleLocation

'        ' apply the battleresult to this unit, this sets the correct battle result
'        AssignbattleResultToGroundChit(unit, batt)

'        Select Case unit.BattleResult
'            Case cmplib01.UnitBattleResult_cgd.Defeat
'                KnockUnitBack(unit, 20, battlelocation)
'                unit.Status = cmplib01.GroundUnitStatus_cgd.Regrouping
'            Case cmplib01.UnitBattleResult_cgd.Draw
'                unit.Status = cmplib01.GroundUnitStatus_cgd.OK
'            Case cmplib01.UnitBattleResult_cgd.MarginalDefeat
'                KnockUnitBack(unit, 10, battlelocation)
'                unit.Status = cmplib01.GroundUnitStatus_cgd.OK
'            Case cmplib01.UnitBattleResult_cgd.MarginalVictory
'                unit.Status = cmplib01.GroundUnitStatus_cgd.OK
'            Case cmplib01.UnitBattleResult_cgd.Victory
'                unit.Status = cmplib01.GroundUnitStatus_cgd.OK
'        End Select
'    End Sub

'    Private Sub ObjectivebattleResult(ByRef obj As InstallationChit, ByVal batt As cmplib01.Battle, ByRef gameData As CampaignerGameData)
'        ' used to apply the correct result to an objective and change ownership

'        AssignbattleResultToGroundChit(obj, batt)

'        ' apply the battleresult to this objective, which sets the correct battle result.
'        ' any victory for the attacker will take ownership of the objective
'        Select Case obj.BattleResult
'            Case cmplib01.UnitBattleResult_cgd.Defeat
'                ' give the objective to the attacker
'                obj.OwningFaction = gameData.Faction_g.HT.Item(CampaignerGameData.CDGKEY_FACTION & batt.AttackingFactionID)
'                '// remove the installation from the attacking factions detection
'                '// and add it to the defending faction's detection!
'                Dim deffact As Faction = gameData.Faction_g.Item(CampaignerGameData.CDGKEY_FACTION & batt.DefendingFactionID)
'                Dim attfact As Faction = gameData.Faction_g.Item(CampaignerGameData.CDGKEY_FACTION & batt.AttackingFactionID)
'                Dim detKey As String
'                For Each detKey In attfact.HTChitDetection.Keys
'                    Debug.WriteLine(detKey)
'                Next

'            Case cmplib01.UnitBattleResult_cgd.MarginalDefeat
'                obj.OwningFaction = gameData.Faction_g.HT.Item(CampaignerGameData.CDGKEY_FACTION & batt.AttackingFactionID)
'                Dim deffact As Faction = gameData.Faction_g.Item(CampaignerGameData.CDGKEY_FACTION & batt.DefendingFactionID)
'                Dim attfact As Faction = gameData.Faction_g.Item(CampaignerGameData.CDGKEY_FACTION & batt.AttackingFactionID)
'                Dim detKey As String
'                For Each detKey In attfact.HTChitDetection.Keys
'                    Debug.WriteLine(detKey)
'                Next

'        End Select

'    End Sub

'    Private Sub KnockUnitBack(ByRef unit As ChitMember, ByVal distance As Int16, ByVal fromLocation As Point)
'        ' if a unit is knocked back into a terrain it can't move into, it should be DESTROYED!!! See CampaignerCombat.txt
'        Dim xStr As Single = GetXorYStrength(cmXorY.cmX, unit.Location.X, fromLocation.X, unit.Location.Y, fromLocation.Y)
'        Dim yStr As Single = GetXorYStrength(cmXorY.cmY, unit.Location.X, fromLocation.X, unit.Location.Y, fromLocation.Y)
'        Dim newLocation As New Point(unit.Location.X, unit.Location.Y)

'        'reverse the values so they move in the correct direction
'        xStr = xStr * -1
'        yStr = yStr * -1

'        newLocation.X = unit.Location.X + (distance * xStr)
'        newLocation.Y = unit.Location.Y + (distance * yStr)
'        unit.Location = newLocation

'    End Sub

'    Private Sub AssignbattleResultToGroundChit(ByRef gChit As ChitMember, ByRef batt As cmplib01.Battle)
'        ' HACK: There is a better way to do this than brute force... figure it out.
'        Select Case gChit.CurrentBattlePosture
'            Case cmplib01.BattlePosture_cgd.Attacking
'                Select Case batt.BattleResult
'                    Case cmplib01.BattleResult_cgd.AttackerVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Victory
'                    Case cmplib01.BattleResult_cgd.AttackerMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
'                    Case cmplib01.BattleResult_cgd.DefenderMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalDefeat
'                    Case cmplib01.BattleResult_cgd.DefenderVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Defeat
'                    Case cmplib01.BattleResult_cgd.Draw : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
'                End Select
'            Case cmplib01.BattlePosture_cgd.AttackingIndirectSupport
'                Select Case batt.BattleResult
'                    Case cmplib01.BattleResult_cgd.AttackerVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
'                    Case cmplib01.BattleResult_cgd.AttackerMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
'                    Case cmplib01.BattleResult_cgd.DefenderMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
'                    Case cmplib01.BattleResult_cgd.DefenderVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Defeat
'                    Case cmplib01.BattleResult_cgd.Draw : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
'                End Select
'            Case cmplib01.BattlePosture_cgd.AttackingReserve
'                Select Case batt.BattleResult
'                    Case cmplib01.BattleResult_cgd.AttackerVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
'                    Case cmplib01.BattleResult_cgd.AttackerMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
'                    Case cmplib01.BattleResult_cgd.DefenderMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
'                    Case cmplib01.BattleResult_cgd.DefenderVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalDefeat
'                    Case cmplib01.BattleResult_cgd.Draw : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
'                End Select
'            Case cmplib01.BattlePosture_cgd.AttackingSupport ' same as indirect support
'                Select Case batt.BattleResult
'                    Case cmplib01.BattleResult_cgd.AttackerVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
'                    Case cmplib01.BattleResult_cgd.AttackerMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
'                    Case cmplib01.BattleResult_cgd.DefenderMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
'                    Case cmplib01.BattleResult_cgd.DefenderVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Defeat
'                    Case cmplib01.BattleResult_cgd.Draw : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
'                End Select
'            Case cmplib01.BattlePosture_cgd.Defending
'                Select Case batt.BattleResult
'                    Case cmplib01.BattleResult_cgd.AttackerVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Defeat
'                    Case cmplib01.BattleResult_cgd.AttackerMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalDefeat
'                    Case cmplib01.BattleResult_cgd.DefenderMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
'                    Case cmplib01.BattleResult_cgd.DefenderVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Victory
'                    Case cmplib01.BattleResult_cgd.Draw : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
'                End Select
'            Case cmplib01.BattlePosture_cgd.DefendingIndirectSupport
'                Select Case batt.BattleResult
'                    Case cmplib01.BattleResult_cgd.AttackerVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalDefeat
'                    Case cmplib01.BattleResult_cgd.AttackerMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
'                    Case cmplib01.BattleResult_cgd.DefenderMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
'                    Case cmplib01.BattleResult_cgd.DefenderVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
'                    Case cmplib01.BattleResult_cgd.Draw : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
'                End Select
'            Case cmplib01.BattlePosture_cgd.DefendingReserve
'                Select Case batt.BattleResult
'                    Case cmplib01.BattleResult_cgd.AttackerVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalDefeat
'                    Case cmplib01.BattleResult_cgd.AttackerMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
'                    Case cmplib01.BattleResult_cgd.DefenderMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
'                    Case cmplib01.BattleResult_cgd.DefenderVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
'                    Case cmplib01.BattleResult_cgd.Draw : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
'                End Select
'            Case cmplib01.BattlePosture_cgd.DefendingSupport ' same as indirect support
'                Select Case batt.BattleResult
'                    Case cmplib01.BattleResult_cgd.AttackerVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalDefeat
'                    Case cmplib01.BattleResult_cgd.AttackerMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
'                    Case cmplib01.BattleResult_cgd.DefenderMarginalVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
'                    Case cmplib01.BattleResult_cgd.DefenderVictory : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.MarginalVictory
'                    Case cmplib01.BattleResult_cgd.Draw : gChit.BattleResult = cmplib01.UnitBattleResult_cgd.Draw
'                End Select
'            Case cmplib01.BattlePosture_cgd.NoBattle
'                gChit.BattleResult = cmplib01.UnitBattleResult_cgd.NoBattle
'        End Select
'    End Sub

'#End Region

'#Region "Properties"
'    Public Property UsesContactCombat() As Boolean Implements ICombatEngine.ICombatEngine.UsesContactCombat
'        Get
'            Return True
'        End Get
'        Set(ByVal Value As Boolean)

'        End Set
'    End Property

'    Public Property UsesPrecombatWindow() As Boolean Implements ICombatEngine.ICombatEngine.UsesPrecombatWindow
'        Get
'            Return True
'        End Get
'        Set(ByVal Value As Boolean)

'        End Set
'    End Property

'    Public Property UsesRangedCombat() As Boolean Implements ICombatEngine.ICombatEngine.UsesRangedCombat
'        Get
'            Return False
'        End Get
'        Set(ByVal Value As Boolean)

'        End Set
'    End Property

'#End Region

'End Class

'Public Module LineDistanceFunctions

'    Public Function DistPointToLine(ByVal hitPtx As Single, ByVal hitPty As Single, ByVal hitPtz As Single, _
'    ByVal TLX1 As Single, ByVal TLY1 As Single, ByVal TLZ1 As Single, ByVal vecXTarg As Single, _
'    ByVal vecYTarg As Single, ByVal vecZTarg As Single, ByRef blnOutOfRange As Boolean) As Single

'        '\\ By MSM: Nov 17, 2003 (Function designed to return the distance from a point to a line)
'        '\\ (A . V) = (ax * vx) + (ay * vy) + (az * vz)
'        '\\ cos(theta) = |A'|/|A|
'        '\\ |A'| = (A . V)/|V| ...... calculates the length of the projected vector
'        '\\ |A - A'| = Sqrt(|A|^2 - |A'|^2)
'        '\\ pythagorean (a^2 + b^2)^.5 = c
'        '\\ theta = acos(|A'|/|A|)

'        Dim TLX2 As Single
'        Dim TLY2 As Single
'        Dim TLZ2 As Single

'        Dim ax As Single
'        Dim ay As Single
'        Dim az As Single

'        Dim ax_norm As Single
'        Dim ay_norm As Single
'        Dim az_norm As Single

'        Dim vx2_norm As Single
'        Dim vy2_norm As Single
'        Dim vz2_norm As Single

'        Dim len_a_squared As Single
'        Dim a_dot_v As Single
'        Dim a_dot_v_norm As Single
'        Dim len_v As Single
'        Dim a_dot_v_over_len_v As Double
'        Dim len_a As Single

'        Dim ptHitPt As New Point
'        Dim ptLineStart As New Point
'        Dim ptLineEnd As New Point

'        Dim m As Single
'        Dim mPerp As Single

'        ptHitPt.X = hitPtx
'        ptHitPt.Y = hitPty
'        ptLineStart.X = TLX1
'        ptLineStart.Y = TLY1

'        TLX2 = TLX1 + vecXTarg
'        TLY2 = TLY1 + vecYTarg
'        TLZ2 = TLZ1 + vecZTarg
'        ptLineEnd.X = TLX2
'        ptLineEnd.Y = TLY2

'        ax = hitPtx - TLX1
'        ay = hitPty - TLY1
'        az = hitPtz - TLZ1

'        m = vecXTarg / vecYTarg

'        If m <> 0 Then
'            mPerp = -(1 / m)
'        End If

'        len_a = Math.Sqrt(ax * ax + ay * ay + az + az)
'        ax_norm = ax / len_a : ay_norm = ay / len_a : az_norm = az / len_a

'        len_a_squared = (ax * ax + ay * ay + az + az)

'        a_dot_v = (ax * vecXTarg) + (ay * vecYTarg) + (az * vecZTarg)

'        len_v = Math.Sqrt(vecXTarg * vecXTarg + vecYTarg * vecYTarg + vecZTarg * vecZTarg)
'        vx2_norm = vecXTarg / len_v : vy2_norm = vecYTarg / len_v : vz2_norm = vecZTarg / len_v
'        a_dot_v_norm = (ax_norm * vx2_norm) + (ay_norm * vy2_norm) + (az_norm * vz2_norm)

'        '\\ given the two points and the hitpoint, determine if the hitpoint falls within the range
'        If IsPtWithinRange(ptHitPt, ptLineStart, ptLineEnd) Then
'            blnOutOfRange = False
'        Else
'            blnOutOfRange = True
'        End If

'        a_dot_v_over_len_v = a_dot_v / len_v

'        Return (CSng(System.Math.Sqrt( _
'            len_a_squared - (CSng(a_dot_v_over_len_v) ^ 2))))

'    End Function

'    Friend Function IsPtWithinRange(ByVal ptHit As Point, ByVal ptLSt As Point, ByVal ptLEnd As Point) As Boolean
'        Dim m As Single
'        Dim mPerp As Single
'        Dim yEqSt As Single
'        Dim yEqEnd As Single

'        'y-y1 = mPerp * (x-x1) : point-slope line equation
'        'y = (mPerp * x) - (mPerp * x1) + y1
'        'm = dy/dx

'        If (ptLEnd.Y - ptLSt.Y) <> 0 Then
'            Select Case (ptLEnd.X - ptLSt.X)
'                Case Is = 0
'                    mPerp = 0
'                    If (ptLEnd.Y > ptLSt.Y) Then
'                        If (ptHit.Y > ptLSt.Y) And (ptHit.Y < ptLEnd.Y) Then
'                            Return True
'                        Else
'                            Return False
'                        End If
'                    Else
'                        If (ptHit.Y > ptLEnd.Y) And (ptHit.Y < ptLSt.Y) Then
'                            Return True
'                        Else
'                            Return False
'                        End If

'                    End If
'                Case Is > 0
'                    m = (ptLEnd.Y - ptLSt.Y) / (ptLEnd.X - ptLSt.X)
'                    mPerp = -(1 / m)
'                    yEqSt = (mPerp * ptHit.X) - (mPerp * ptLSt.X) + ptLSt.Y
'                    yEqEnd = (mPerp * ptHit.X) - (mPerp * ptLEnd.X) + ptLEnd.Y
'                    If yEqSt > yEqEnd Then
'                        If ptHit.Y > yEqEnd And ptHit.Y < yEqSt Then
'                            Return True
'                        Else
'                            Return False
'                        End If
'                    Else
'                        If ptHit.Y > yEqSt And ptHit.Y < yEqEnd Then
'                            Return True
'                        Else
'                            Return False
'                        End If
'                    End If

'                Case Is < 0
'                    m = (ptLEnd.Y - ptLSt.Y) / (ptLEnd.X - ptLSt.X)
'                    mPerp = -(1 / m)
'                    yEqSt = (mPerp * ptHit.X) - (mPerp * ptLSt.X) + ptLSt.Y
'                    yEqEnd = (mPerp * ptHit.X) - (mPerp * ptLEnd.X) + ptLEnd.Y
'                    If yEqSt > yEqEnd Then
'                        If ptHit.Y > yEqEnd And ptHit.Y < yEqSt Then
'                            Return True
'                        Else
'                            Return False
'                        End If
'                    Else
'                        If ptHit.Y > yEqSt And ptHit.Y < yEqEnd Then
'                            Return True
'                        Else
'                            Return False
'                        End If
'                    End If
'            End Select
'        Else
'            'dy = 0
'            If (ptLSt.X > ptLEnd.X) Then
'                If (ptHit.X > ptLEnd.X) And (ptHit.X < ptLSt.X) Then
'                    Return True
'                Else
'                    Return False
'                End If
'            Else
'                If (ptHit.X > ptLSt.X) And (ptHit.X < ptLEnd.X) Then
'                    Return True
'                Else
'                    Return False
'                End If
'            End If
'        End If

'    End Function

'End Module
